/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package variante_puzle;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JOptionPane;

/**
 * @author Gaby
 */
public class LlenarCruz {

    private static int[][] matriz = new int[3][4];
    private static List<Integer> listaAlt = new ArrayList();
    private static boolean solucion;
    private static Random r = new Random();
    private static int error;

    /**
     * Metodo numAleatorios permite generar una lista con elementos asignados de forma aleatoria
     * @return lista con elementos de tipo entero
     * Los elementos de esta lista posteriormente se dispondran(mediante el metodo matrizAleatoria) en una matriz.
     */
    public static List<Integer> numAleatorios() {
        int n = 0;
        for (int i = 0; i < 8; i++) {
            n = Math.abs(r.nextInt()) % 9;//escoge de forma aleatoria un numero de entre los digitos del 0 al 9
            if (!listaAlt.contains(n) && (n != 0 && n != 9)) {//controla que en la lista solo se agreguen los digitos del 1 al 8 sin repetirse
                listaAlt.add(n);
            } else {

                i--;
            }
        }
        return listaAlt;
    }

    /**
     * Metodo matrizAleatoria genera una matriz, cuyos elementos son los generados de forma aleotoria con el metodo numAleatorios
     * @param l, es la lista de tipo entero que contiene los elementos a agregarse en la matriz
     * @return una matriz de 3x4
     */
    public static int[][] matrizAleatoria(List<Integer> l) {
        int pos = 0;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 4; j++) {
                if ((i == 0 && j == 0) || (i == 0 && j == 3) || (i == 2 && j == 0) || (i == 2 && j == 3)) {
                    matriz[i][j] = 0;
                } else {
                    matriz[i][j] = l.get(pos);//asigna a una celda de la matriz uno de los elementos de la lista l que ingresa como parametro de este metodo
                    pos++;
                }
            }
        }
        return matriz;
    }

    /**
     * Metodo adyacencia permite verificar si existe o no adyacencia entre los elementos de la matriz generada con el metodo matrizAleatoria
     * @param matriz, es la matriz de orden 3x4 que fue obtenida a con el metodo matrizAleatoria
     * @return un valor de tipo booleano
     * Em metodo consiste en comparar si el sucesor y antecesor de un elemento de la matriz esta adyacente a dicho numero.
     * Lo que se desea es obtener un valor de verdad TRUE que indique que no existe adyacencia, en caso contrario FALSE indica
     * la adyacencia entre elementos.
     */
    public static void adyanecia(int matriz[][]) {
        solucion = true;
        error = 0;
        int n1 = matriz[1][0];
        int n2 = matriz[1][1];
        int n3 = matriz[1][2];
        int n4 = matriz[1][3];

        for (int i = 0; i < 3; i++) {//recorre las filas de la matriz
            if ((n1 + 1) == matriz[i][1]) {
                solucion = false;
                error++;
                System.out.print("Adyacencia entre" + n1 + " y " + matriz[i][1] + "\n");
            } else if ((n1 - 1) == matriz[i][1]) {
                solucion = false;
                error++;
                System.out.print("Adyacencia entre" + n1 + " y " + matriz[i][1] + "\n");
            }
            if ((n4 + 1) == matriz[i][2]) {
                solucion = false;
                error++;
                System.out.print("Adyacencia entre" + n4 + " y " + matriz[i][2] + "\n");
            } else if ((n4 - 1) == matriz[i][2]) {
                solucion = false;
                error++;
                System.out.print("Adyacencia entre" + n4 + " y " + matriz[i][2] + "\n");
            }
            if ((n2 + 1) == matriz[i][1] || (n2 - 1) == matriz[i][1]) {
                solucion = false;
                error++;
                System.out.print("Adyacencia entre" + n2 + " y " + matriz[i][1] + "\n");
            } else if ((n2 + 1) == matriz[i][2] || (n2 - 1) == matriz[i][2]) {
                solucion = false;
                error++;
                System.out.print("Adyacencia entre" + n2 + " y " + matriz[i][2] + "\n");
            }

            if ((n3 + 1) == matriz[i][1] || (n3 - 1) == matriz[i][1]) {
                solucion = false;
                error++;
                System.out.print("Adyacencia entre" + n3 + " y " + matriz[i][1] + "\n");
            } else if ((n3 + 1) == matriz[i][2] || (n3 - 1) == matriz[i][2]) {
                solucion = false;
                error++;
                System.out.print("Adyacencia entre" + n3 + " y " + matriz[i][2] + "\n");
            }


        }
        if ((matriz[0][1] + 1 == matriz[0][2]) || (matriz[0][1] - 1 == matriz[0][2])) {
            solucion = false;
            System.out.print("Adyacencia entre" + matriz[0][1] + " y " + matriz[0][2] + "\n");
            error++;
        } else if ((matriz[2][1] + 1 == matriz[2][2]) || (matriz[2][1] - 1 == matriz[2][2])) {
            solucion = false;
            error++;
            System.out.print("Adyacencia entre" + matriz[2][1] + " y " + matriz[2][2] + "\n");
        }
//        return solucion;
    }

    /**
     * metodo Imprimir permite presentar en pantalla una matriz con sus elementos
     */
    public static void imprimir() {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 4; j++) {
                System.out.print(matriz[i][j] + "\t");
            }
            System.out.print("\n");
        }
    }

    public static void main(String args[]) {
        /**
         *El metodo adyacencia se va a jecutar n veces,
         * para verificar su comportamiento. Para esto se incluye al metodo en
         * un ciclo que se ejecutara el numero de veces que se indique como parametro
         * Ademas se miden los tiempo de ejecucion en nanosegundo(ns)
         */
        int op = Integer.parseInt(JOptionPane.showInputDialog(null, "Ingrese el numero de iteraciones:"));
        int err = 0;
        int aux = 0;
        int c = 1;
        //obtiene el tiempo de incio de ejecucion del programa milisegundos
        long tInicio1 = System.currentTimeMillis();
        //obtiene el tiempo de incio de ejecucion del programa nanosegundo
        long tInicio = System.nanoTime();

        //ESTAS LINEAS DE CODIGO PERMITEN EJECUTAR EL METODO ADYACENCIA LAS VECES QUE SE LE INDIQUE
        for (int i = 0; i < op; i++) {
            //tiempo de inicio por cada iteracion
            long tInicioIteracion = System.nanoTime();
            System.out.println("Iteracion: " + c);

            //llamada al metodo adyacencia
            adyanecia(matrizAleatoria(numAleatorios()));

            System.out.println("Total Errores: " + error + "\n");
            //presentacion de la matriz generada
            imprimir();
            //encerar la lista, esto permite seguir generando nuevas matrices
            listaAlt.clear();
            //verifica cual es la matriz con menor numero de errores
            if (err != 0) {
                if (error < err) {
                    err = error;
                    aux = c;
                }
            } else {
                err = error;
                aux = c;
            }
            long tiempoEjec = System.nanoTime() - tInicioIteracion;
            System.out.println("El tiempo de ejecucion de la Iteracion " + c + " : " + tiempoEjec + " ns");
            c++;
            System.out.println("-----------------------------------\n");
        }

        System.out.println("Menor numero de adyacencias " + err + " en la Iteracion " + aux);
        // determina el tiempo total de ejecucion del programa en milisegundo
        long tTotalMs = System.currentTimeMillis() - tInicio1;
        // determina el tiempo total de ejecucion del programa en nanosegundos
        long tTotalNs = System.nanoTime() - tInicio;
        System.out.println("El tiempo de ejecucion total: " + tTotalMs + " ms");
        System.out.println("El tiempo de ejecucion total: " + tTotalNs + " ns");
    }
}
